#include "stdafx.h"

BOOL WndGrid::isClassRegistered = FALSE;
TCHAR WndGrid::wndClassName[MAX_LOADSTRING] = TEXT("WndClass_Grid");
int WndGridCtlr::xChar, WndGridCtlr::xCaps, WndGridCtlr::yChar, WndGridCtlr::xClient, WndGridCtlr::yClient;

SheetView WndGridCtlr::SheetViewer;

int WndGridCtlr::iDeltaPerline, WndGridCtlr::iAccumDelta;
ULONG WndGridCtlr::ulScrollLines;
WNDPROC WndGridCtlr::EditProc = 0;

WndGridCtlr::MOVING_TYPE WndGridCtlr::movingType;

HWND WndGridCtlr::hEditBox = 0;
/***************************************
* The Constructor of WndGrid
* The parameters are almost the same as CreateWindow()
***/
WndGrid::WndGrid(LPCTSTR WndText, DWORD dwStyle, 
				 int x,  int y ,  int nWidth,  int nHeight,
				 HWND hWndParent,  HMENU hMenu,  HINSTANCE hInstance, LPVOID lpParam)
{
	MyCreateWindow(WndText, dwStyle, x,y, nWidth, nHeight, 
		hWndParent, hMenu, hInstance, lpParam);
	if(pWndController!= 0)
		delete pWndController;
	pWndController = new WndGridCtlr();
}

/***************************************
 * Registering Window Class
 ***/
ATOM WndGrid::MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wcex.lpfnWndProc	= &Application::AppWndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SpreadSheet));
	wcex.hCursor		= LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_DEFAULT));
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= wndClassName;
	wcex.hIconSm		= 0;

	return RegisterClassEx(&wcex);
}

//-----------------------Controller------------------------

/***************************************
* Registering Message Mapping
***/
WndGridCtlr::WndGridCtlr()
{
	MsgMappingItem Item[] = 
	{
		/* MSG */
		MsgMappingItem(WM_CREATE, &WndGridCtlr::OnCreate),
		MsgMappingItem(WM_PAINT, &WndGridCtlr::OnPaint),
		MsgMappingItem(WM_SIZE, &WndGridCtlr::OnSize),
		MsgMappingItem(WM_ERASEBKGND, &WndGridCtlr::OnEraseBG),

		/* WM_KEYDOWN */
		MsgMappingItem(WM_KEYDOWN, &WndGridCtlr::OnKeyDown),
		MsgMappingItem(WM_CHAR, &WndGridCtlr::OnChar),

		/* Mouse */
		MsgMappingItem(WM_MOUSEMOVE, &WndGridCtlr::OnMouseMove),
		MsgMappingItem(WM_LBUTTONUP, &WndGridCtlr::OnMouseUp),
		MsgMappingItem(WM_LBUTTONDOWN, &WndGridCtlr::OnMouseDown),
		MsgMappingItem(WM_RBUTTONDOWN, &WndGridCtlr::OnMouseRight),
		MsgMappingItem(WM_LBUTTONDBLCLK, &WndGridCtlr::OnMouseDouble),
		MsgMappingItem(WM_MOUSEWHEEL, &WndGridCtlr::OnMouseWheel),

		/* SCROLL BAR*/
		MsgMappingItem(WM_VSCROLL, &WndGridCtlr::OnVScroll),
		MsgMappingItem(WM_HSCROLL, &WndGridCtlr::OnHScroll),

		/* WM_COMMAND */
		/* EDITBOX*/
		MsgMappingItem(ID_EDITBOX, &WndGridCtlr::EditBox),

		/* CUSTOM */
		// Reload width and height
		MsgMappingItem(MSG_GRID_REFRESH, &WndGridCtlr::RefreshGridData),
		MsgMappingItem(MSG_GRID_INSERTROW, &WndGridCtlr::InsertRow),
		MsgMappingItem(MSG_GRID_INSERTCOL, &WndGridCtlr::InsertCol),
		MsgMappingItem(MSG_GRID_REMOVEROW, &WndGridCtlr::RemoveRow),
		MsgMappingItem(MSG_GRID_REMOVECOL, &WndGridCtlr::RemoveCol),
		MsgMappingItem(MSG_GRID_ONCOPY, &WndGridCtlr::OnCopy),
		MsgMappingItem(MSG_GRID_ONCUT, &WndGridCtlr::OnCut),
		MsgMappingItem(MSG_GRID_ONPASTE, &WndGridCtlr::OnPaste),
		MsgMappingItem(MSG_GRID_TEXTCOLOR, &WndGridCtlr::OnSetTextColor),
		MsgMappingItem(MSG_GRID_BACKCOLOR, &WndGridCtlr::OnSetBackColor),
		MsgMappingItem(MSG_GRID_STYLECLEAR, &WndGridCtlr::OnStyleClear),
		MsgMappingItem(MSG_GRID_SELECTALL, &WndGridCtlr::OnSelectAll),
		MsgMappingItem(MSG_GRID_GOTO, &WndGridCtlr::OnGoto),
		MsgMappingItem(MSG_GRID_ALIGN, &WndGridCtlr::OnAlign),
		MsgMappingItem(MSG_GRID_VALIGN, &WndGridCtlr::OnVAlign),
		MsgMappingItem(MSG_GRID_FONT, &WndGridCtlr::OnFontSelect),
		MsgMappingItem(MSG_GRID_FONTATTR, &WndGridCtlr::OnFontAttr),
	};

	// Append Message Mapping
	for (int i =0 ; i< sizeof(Item)/sizeof(MsgMappingItem) ; i++)
	{
		MappingTable.Append(Item[i]);
	}
}

LRESULT CALLBACK WndGridCtlr::OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	// For mouse wheel support
	::SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0, &ulScrollLines, 0);

	if (ulScrollLines)
	{
		iDeltaPerline = WHEEL_DELTA / ulScrollLines;
	}
	else
	{
		iDeltaPerline = 0;
	}

	// Get HDC info
	HDC hdc;
	TEXTMETRIC tm;
	hdc = GetDC(hWnd);
	GetTextMetrics(hdc, &tm);
	xChar = tm.tmAveCharWidth;
	xCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar / 2;
	yChar = tm.tmHeight + tm.tmExternalLeading;
	ReleaseDC (hWnd, hdc);
	//SetTimer (hwnd, 1, uiMsecInterval, NULL) ;
	
	return 0;
}

LRESULT CALLBACK WndGridCtlr::InsertRow(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.InsertRow(SheetViewer.GetSelecting().iRow);
	InvalidateRect(hWnd, NULL, NULL);
	return 0;
}
LRESULT CALLBACK WndGridCtlr::InsertCol(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.InsertCol(SheetViewer.GetSelecting().iCol);
	InvalidateRect(hWnd, NULL, NULL);
	return 0;
}
LRESULT CALLBACK WndGridCtlr::RemoveRow(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.RemoveRow(SheetViewer.GetSelecting().iRow);
	InvalidateRect(hWnd, NULL, NULL);
	return 0;
}
LRESULT CALLBACK WndGridCtlr::RemoveCol(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.RemoveCol(SheetViewer.GetSelecting().iCol);
	InvalidateRect(hWnd, NULL, NULL);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	if (movingType != COL_WIDTH && movingType!= ROW_HEIGHT)
	{
		RefreshGridData(hWnd, 0, 0);
	}
	ResizeScrollBar(hWnd);
	PAINTSTRUCT ps;
	HDC hdc = ::BeginPaint(hWnd, &ps);

	HDC hdcMem;			// hdc in memory
	HBITMAP hBitmap;	// bitmap buffer
	HGDIOBJ hOldObject; // old hdc
	RECT rcClient;

	// Copy HDC to Memory
	GetClientRect(hWnd,&rcClient);
	hdcMem = CreateCompatibleDC(hdc);
	hBitmap = CreateCompatibleBitmap(hdc,rcClient.right-rcClient.left,rcClient.bottom-rcClient.top);
	hOldObject = SelectObject(hdcMem,hBitmap);

	// Do as WM_ERASEBKGND 
	FillRect(hdcMem,&rcClient,(HBRUSH) GetStockObject(WHITE_BRUSH));

	// Change the coordinate to avoid ToolBar covering the client-area.
	//::SetViewportOrgEx(hdc, 0, 0, NULL);

	// Draw to hdcMem
	::SetBkMode(hdcMem, TRANSPARENT);
	drawGrid(hdcMem);

	BitBlt(hdc,rcClient.left,rcClient.top,rcClient.right-rcClient.left,rcClient.bottom-rcClient.top,hdcMem,0,0,SRCCOPY);

	SelectObject(hdcMem,hOldObject);
	DeleteObject(hBitmap);
	DeleteDC(hdcMem);

	EndPaint(hWnd,&ps);

	return 0;
}

/* WM_SIZE */
LRESULT CALLBACK WndGridCtlr::OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	xClient = LOWORD(lParam);
	yClient = HIWORD(lParam);

	SheetViewer.SetClientSize(xClient, yClient);
	SheetViewer.ReadColumnWidth();
	SheetViewer.ReadRowHeight();

	UpdateWindow(hWnd);

	return 0;
}

/* WM_LBUTTONUP */
LRESULT CALLBACK WndGridCtlr::OnMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	POINT PT = {static_cast<short>(LOWORD(lParam)),static_cast<short>(HIWORD(lParam))};//{LOWORD(lParam),HIWORD(lParam)};
	ReleaseCapture();
	ROW_NUM iRow = 0;
	COL_NUM iCol = 0;
	SheetView::AREA area = SheetViewer.CheckArea(PT.x, PT.y, iRow, iCol);
	int NewWidth, NewHeight;
	SheetController SheetCtlr;
	
	switch(movingType)
	{
	case CELL_SELECT:
		SheetViewer.SetRegionEnd(iRow, iCol);
		::SendMessage(::GetParent(hWnd), MSG_MAIN_SHOWSELECTCELL, (WPARAM)iRow, (LPARAM)iCol);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case COL_WIDTH:
		SheetViewer.EndSetColWidth(iCol, NewWidth);
		SheetCtlr.SetColWidth(iCol, NewWidth);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case ROW_HEIGHT:
		SheetViewer.EndSetRowHeight(iRow, NewHeight);
		SheetCtlr.SetRowHeight(iRow, NewHeight);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	default:
		break;
	}
	movingType = NONE;
	return 0;
}

/* WM_MOUSEMOVE */
LRESULT CALLBACK WndGridCtlr::OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	POINT PT = {static_cast<short>(LOWORD(lParam)),static_cast<short>(HIWORD(lParam))};
	CELLPOS pos;
	SheetView::AREA area = SheetViewer.CheckArea(PT.x, PT.y, pos.iRow, pos.iCol);
	
	HCURSOR hCursor;
	switch(area)
	{
	case SheetView::COL_HEADER:
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_COL));
		SetCursor(hCursor);
		break;
	case SheetView::ROW_HEADER:
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_ROW));
		SetCursor(hCursor);
		break;
	case SheetView::COL_LINE:
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_WIDTH));
		SetCursor(hCursor);
		break;
	case SheetView::ROW_LINE:
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_HEIGHT));
		SetCursor(hCursor);
	case SheetView::GRID_AREA:
		break;
	default:
		break;
	}
	if (wParam && MK_LBUTTON)	
	{
		switch(movingType)
		{
		case COL_SELECT:
			hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_COL));
			SetCursor(hCursor);
			selectCol(hWnd, pos.iCol, true);
			InvalidateRect(hWnd, NULL, TRUE);
			return 0;
			break;
		case ROW_SELECT:
			hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_ROW));
			SetCursor(hCursor);
			selectRow(hWnd, pos.iRow, true);
			InvalidateRect(hWnd, NULL, TRUE);
			return 0;
			break;
		case COL_WIDTH:
			hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_WIDTH));
			SetCursor(hCursor);
			SheetViewer.SetColWidth(PT.x);
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		case ROW_HEIGHT:
			hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_HEIGHT));
			SetCursor(hCursor);
			SheetViewer.SetRowHeight(PT.y);
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		case CELL_SELECT:
			//Moving with the left button down
			if (wParam && MK_LBUTTON)	
			{
				selectCell(hWnd, pos, true);
				InvalidateRect(hWnd, NULL, TRUE);
				return 0;
			}
			break;
		default:
			break;
		}
	}
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	HideEditBox();
	SetCapture(hWnd);
	POINT PT = {LOWORD(lParam),HIWORD(lParam)};
	CELLPOS pos;
	SheetView::AREA area = SheetViewer.CheckArea(PT.x, PT.y, pos.iRow, pos.iCol);
	HCURSOR hCursor;
	switch(area)
	{
	case SheetView::COL_HEADER:
		movingType = COL_SELECT;
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_COL));
		SetCursor(hCursor);
		selectCol(hWnd, pos.iCol, false);
		break;

	case SheetView::ROW_HEADER:
		movingType = ROW_SELECT;
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_SELECT_ROW));
		SetCursor(hCursor);
		selectRow(hWnd, pos.iRow, false);
		break;

	case SheetView::COL_LINE:
		movingType = COL_WIDTH;
		SheetViewer.BeginSetColWidth(pos.iCol);
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_WIDTH));
		SetCursor(hCursor);
		break;

	case SheetView::ROW_LINE:
		movingType = ROW_HEIGHT;
		SheetViewer.BeginSetRowHeight(pos.iRow);
		hCursor = ::LoadCursor(Application::hInst, MAKEINTRESOURCE(IDC_ADJ_HEIGHT));
		SetCursor(hCursor);
		break;

	case SheetView::GRID_AREA:
		movingType = CELL_SELECT;
		if (GetKeyState(VK_SHIFT)<0)
			selectCell(hWnd, pos,true);
		else
			selectCell(hWnd, pos,false);
		::SendMessage(::GetParent(hWnd), MSG_MAIN_SHOWSELECTCELL, (WPARAM)pos.iRow, (LPARAM)pos.iCol);
		::InvalidateRect(hWnd, NULL, TRUE);
		break;
	case SheetView::CORNER_BUTTON:
		movingType = NONE;
		OnSelectAll(hWnd, 0,0);
		break;
	default:
		movingType = NONE;
		break;
	}
	return 0;
}

/* WM_LBUTTONDBL */
LRESULT CALLBACK WndGridCtlr::OnMouseDouble(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	const CELLPOS cell = SheetViewer.GetSelecting();
	RECT rectCell = SheetViewer.GetSelectingRect();

	SheetController objSheetCtlr;
	wstring content;
	CellDataItem item;
	if (objSheetCtlr.GetCellContent(SheetViewer.GetSelecting(), item))
	{
		CreateEditBox(hWnd, rectCell, &item);
		::SetWindowText(hEditBox, item.pContent->c_str());
		//::SendMessage(hEditBox, EM_SETC)

	}
	else
	{
		CreateEditBox(hWnd, rectCell, 0);
	}
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnMouseRight(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	HideEditBox();
	POINT PT = {LOWORD(lParam),HIWORD(lParam)};
	CELLPOS pos;
	SheetView::AREA area = SheetViewer.CheckArea(PT.x, PT.y, pos.iRow, pos.iCol);
	HMENU hContextMenu = LoadMenu(Application::hInst, MAKEINTRESOURCE(IDR_TABLEMENU));
	HMENU hMenu;

	switch(area)
	{
	case SheetView::COL_HEADER:
		selectCol(hWnd, pos.iCol,false);
		hMenu = GetSubMenu(hContextMenu, 1);
		ClientToScreen(hWnd, &PT);
		TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, PT.x, PT.y, 0, GetParent(hWnd), NULL);
		break;

	case SheetView::ROW_HEADER:
		selectRow(hWnd, pos.iRow, false);
		hMenu = GetSubMenu(hContextMenu,0);
		ClientToScreen(hWnd, &PT);
		TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, PT.x, PT.y, 0, GetParent(hWnd), NULL);
		break;
	case SheetView::CORNER_BUTTON:
		OnSelectAll(hWnd, 0,0);
		hMenu = GetSubMenu(hContextMenu,3);
		ClientToScreen(hWnd, &PT);
		TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, PT.x, PT.y, 0, GetParent(hWnd), NULL);
		break;
	case SheetView::GRID_AREA:
		if (!SheetViewer.InRegion(pos))
			selectCell(hWnd, pos, false);
		hMenu = GetSubMenu(hContextMenu,2);
		CheckMenu(hMenu);
		ClientToScreen(hWnd, &PT);
		TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, PT.x, PT.y, 0, GetParent(hWnd), NULL);
		break;
	default:
		break;
	}
	::DestroyMenu(hContextMenu);
	return 0;
}

/* WM_ERASEBKGND */
LRESULT CALLBACK WndGridCtlr::OnEraseBG(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnCopy(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController Ctrl;
	Ctrl.CopyRegion(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd());
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnCut(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController Ctrl;
	Ctrl.CutRegion(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd());
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnPaste(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController Ctrl;
	Ctrl.Paste(SheetViewer.GetSelecting());
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	CELLPOS pos = SheetViewer.GetRegionEnd();
	SheetController objSheetCtlr;
	bool multiSel = false;
	if(::GetKeyState(VK_SHIFT) < 0)
		multiSel = true;

	switch(wParam)
	{
	case VK_PRIOR:
		SendMessage(hWnd, WM_VSCROLL, SB_PAGEUP, 0);
		break;
	case VK_NEXT:
		SendMessage(hWnd, WM_VSCROLL, SB_PAGEDOWN, 0);
		break;
	case VK_UP:
		pos.iRow --;
		selectCell(hWnd, pos, multiSel);
		break;
	case VK_DOWN:
	case VK_RETURN:
		pos.iRow++;
		selectCell(hWnd, pos, multiSel);
		break;
	case VK_LEFT:
		pos.iCol--;
		selectCell(hWnd, pos, multiSel);
		break;
	case VK_TAB:
	case VK_RIGHT:
		pos.iCol++;
		selectCell(hWnd, pos, multiSel);
		break;
	case VK_DELETE:
		objSheetCtlr.DeleteRegion(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd());
		InvalidateRect(hWnd, NULL, FALSE);
		break;
	default:
		return ::DefWindowProc(hWnd, WM_KEYDOWN, wParam, lParam);
		break;
	}
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnChar(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	if (wParam == 0x09 || wParam == 0x0D)
	{
		return 0;
	}
	const CELLPOS cell = SheetViewer.GetSelecting();
	RECT rectCell = SheetViewer.GetSelectingRect();

	CreateEditBox(hWnd, rectCell);
	::SendMessage(hEditBox, WM_CHAR, wParam, lParam);

	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnMouseWheel(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	if (iDeltaPerline ==0)
	{
		return 0;
	}
	iAccumDelta+=(short)HIWORD(wParam);
	while (iAccumDelta >= iDeltaPerline)
	{
		::SendMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0);
		iAccumDelta -= iDeltaPerline;
	}

	while (iAccumDelta <= - iDeltaPerline)
	{
		::SendMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0);
		iAccumDelta += iDeltaPerline;
	}
	return 0;
}

/* WM_VSCROLL */
LRESULT CALLBACK WndGridCtlr::OnVScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	return scroll(hWnd, SB_VERT, wParam, lParam);
}

/* WM_HSCROLL */
LRESULT CALLBACK WndGridCtlr::OnHScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	return scroll(hWnd, SB_HORZ, wParam, lParam);
}

LRESULT CALLBACK WndGridCtlr::scroll(HWND hWnd, int nBar, WPARAM wParam, LPARAM lParam)
{
	
	SCROLLINFO si;
	si.cbSize = sizeof(si);

	si.fMask = SIF_ALL;
	::GetScrollInfo(hWnd, nBar, &si);
	
	switch(LOWORD(wParam))
	{
	case SB_TOP:
		si.nPos = si.nMin;
		break;
	case SB_BOTTOM:
		si.nPos = si.nMax;
		break;
	case SB_LINEUP:
		si.nPos--;
		break;
	case SB_LINEDOWN:
		si.nPos++;
		break;
	case SB_PAGEUP:		
		si.nPos -= si.nPage;
		break;
	case SB_PAGEDOWN:
		// Reset the page
		/*si.fMask = SIF_PAGE;
		si.nPage = yClient / CELL_DEFHEIGHT;
		::SetScrollInfo(hWnd, nBar, &si, FALSE);*/
		
		si.nPos += si.nPage;
		break;
	case SB_THUMBTRACK:
		si.nPos = si.nTrackPos;
		break;
	default:
		break;
	}


	si.fMask = SIF_POS;
	SetScrollInfo(hWnd, nBar, &si, FALSE);

	const CELLPOS leftCornerCell = SheetViewer.GetLeftCorner();

	if (si.nPos != ((nBar == SB_VERT) ? leftCornerCell.iRow : leftCornerCell.iCol))
	{
		if (si.nPos >= si.nMin && si.nPos <= si.nMax )
		{
			if (nBar == SB_VERT)
			{
				SheetViewer.SetLeftCorner(si.nPos, leftCornerCell.iCol);
			}
			else
			{
				SheetViewer.SetLeftCorner(leftCornerCell.iRow , si.nPos);
			}
		}
	}
	RefreshGridData(hWnd, 0,0);
	return 0;
}

void WndGridCtlr::ResizeScrollBar(HWND hWnd)
{
	// Redraw Scroll Bar
	// Vertical Scroll Bar
	SCROLLINFO si;
	si.cbSize = sizeof(si);
	si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
	si.nPos = SheetViewer.GetLeftCorner().iRow;
	si.nMin = 1;
	si.nMax = SheetViewer.GetLeftCorner().iRow + SheetViewer.GetRowLinesCount() + 10;
	si.nMax = si.nMax > ROW_MAX+2 ? ROW_MAX+2 : si.nMax;
	
	si.nPage = yClient / (int)(CELL_DEFHEIGHT* ApplicationSetting::Zooming);
	si.nPage = min((int)si.nPage, (int)(si.nMax-si.nMin));
	::SetScrollInfo(hWnd, SB_VERT, &si, TRUE);


	// Horizontal Scroll Bar
	si.cbSize = sizeof(si);
	si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
	si.nPos = SheetViewer.GetLeftCorner().iCol;
	si.nMin = 1;
	si.nMax = SheetViewer.GetLeftCorner().iCol + SheetViewer.GetColLinesCount() + 7;
	si.nMax = si.nMax > COL_MAX+2 ? COL_MAX+2 : si.nMax;
	si.nPage = xClient / (int)(CELL_DEFWIDTH* ApplicationSetting::Zooming);
	si.nPage = min((int)si.nPage, (int)(si.nMax-si.nMin));
	::SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
}

LRESULT CALLBACK WndGridCtlr::RefreshGridData(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetViewer.ReadRowHeight();
	SheetViewer.ReadColumnWidth();
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnSetTextColor(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctlr;
	ctlr.SetColor(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_TXCOLOR, (COLORREF)wParam);
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnSetBackColor(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctlr;
	ctlr.SetColor(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_BKCOLOR, (COLORREF)wParam);
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnStyleClear(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctlr;
	ctlr.SetColor(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), 0, 0, true);
	CheckToolBarButton();
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnSelectAll(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	CELLPOS pos;
	pos.iRow = 1;
	pos.iCol = 1;
	selectCell(hWnd, pos, false);
	SheetViewer.SetRegionEnd(ROW_MAX, COL_MAX, false, false);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnGoto(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	CELLPOS pos;
	pos.iRow = (ROW_NUM)wParam;
	pos.iCol = (COL_NUM)lParam;
	selectCell(hWnd, pos, false);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnAlign(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.SetAlign(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_HALIGN, wParam);
	CheckToolBarButton();
	CheckMenu(::GetMenu(::GetParent(hWnd)));
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnVAlign(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.SetAlign(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_VALIGN, wParam);
	CheckToolBarButton();
	CheckMenu(::GetMenu(::GetParent(hWnd)));
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnFontSelect(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	FontDialog fd(hWnd);
	LOGFONT lg;
	::ZeroMemory(&lg, sizeof(lg));

	CellDataItem item;
	SheetController ctrl;
	if(ctrl.GetCellContent(SheetViewer.GetSelecting(), item))
	{
		_tcscpy_s(lg.lfFaceName,32,item.pFontName->c_str());
		lg.lfItalic = item.fontAttr & CELL_FONT_ATTR_ITALIC;
		lg.lfStrikeOut = item.fontAttr & CELL_FONT_ATTR_STRIKEOUT;
		lg.lfUnderline = item.fontAttr & CELL_FONT_ATTR_UNDERLINE;
		lg.lfWeight = item.fontAttr & CELL_FONT_ATTR_BOLD ? 700 : 0;
	}
	else
	{
		_tcscpy_s(lg.lfFaceName,32, CELL_DEF_FONT_NAME);
	}
	if(fd.ChooseFontDlg(&lg))
	{
		UINT attr = 0;
		attr += lg.lfStrikeOut ? CELL_FONT_ATTR_STRIKEOUT : 0;
		attr += lg.lfUnderline ? CELL_FONT_ATTR_UNDERLINE : 0;
		attr += lg.lfItalic ? CELL_FONT_ATTR_ITALIC : 0;
		attr += lg.lfWeight == 700 ? CELL_FONT_ATTR_BOLD : 0;
		ctrl.SetFont(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_FONT, lg.lfFaceName, attr);	
	}
	CheckToolBarButton();
	CheckMenu(::GetMenu(::GetParent(hWnd)));
	InvalidateRect(hWnd, &SheetViewer.GetRegionRect(), true);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::OnFontAttr(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	SheetController ctrl;
	ctrl.SetFontAttr(SheetViewer.GetRegionStart(), SheetViewer.GetRegionEnd(), CELL_MF_FONTATTR, wParam);
	CheckToolBarButton();
	CheckMenu(::GetMenu(::GetParent(hWnd)));
	InvalidateRect(hWnd, NULL, TRUE);
	return 0;
}

LRESULT CALLBACK WndGridCtlr::EditBoxProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_KEYDOWN :
		if (wParam == VK_TAB || wParam == VK_RETURN)
		{
			HWND hParent = ::GetParent(hWnd);
			HideEditBox();
			::SendMessage(hParent, WM_KEYDOWN, wParam, lParam);
			return 0;	
		}
		break;

	case WM_DESTROY:
		HDC hdc = GetDC(hWnd);
		::DeleteObject(::SelectObject(hdc, ::GetStockObject(SYSTEM_FONT)));
		::ReleaseDC(hWnd,hdc);
		break;
	}

	return CallWindowProc (EditProc, hWnd, message, wParam, lParam);
}

/* ID_EDITBOX */
LRESULT CALLBACK WndGridCtlr::EditBox(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	wmId    = LOWORD(wParam);
	wmEvent = HIWORD(wParam);
	switch(wmEvent)
	{
	case EN_CHANGE:
		//::MessageBox(hWnd, L"Changed!", L"", NULL);	
		break;
	}
	return ::DefWindowProc(hWnd,WM_COMMAND, wParam,lParam);
}


//--------- Private Functions ---------
void WndGridCtlr::selectCell(HWND hWnd, CELLPOS& pos, bool multiCell)
{
	if (pos.iRow>0 && pos.iRow <= ROW_MAX && pos.iCol >0 && pos.iCol <=COL_MAX)
	{
		if (!multiCell)
		{
			SheetViewer.SetSelectingCell(pos.iRow,pos.iCol);
			SheetViewer.SetRegionStart(pos.iRow, pos.iCol);
			::SendMessage(::GetParent(hWnd), MSG_MAIN_SHOWSELECTCELL, (WPARAM)pos.iRow, (LPARAM)pos.iCol);
			CheckToolBarButton();
			CheckMenu(::GetMenu(::GetParent(hWnd)));
		}
		SheetViewer.SetRegionEnd(pos.iRow, pos.iCol);
		::InvalidateRect(hWnd, NULL, TRUE);
	}
}

void WndGridCtlr::selectRow(HWND hWnd, ROW_NUM iRow, bool multi)
{
	if (iRow>0 && iRow <= ROW_MAX)
	{
		if (!multi)
		{
			SheetViewer.SetSelectingCell(iRow, 1);
			SheetViewer.SetRegionStart(iRow, 1);
			::SendMessage(::GetParent(hWnd), MSG_MAIN_SHOWSELECTCELL, (WPARAM)iRow, (LPARAM)1);
		}
		SheetViewer.SetRegionEnd(iRow, COL_MAX, false ,true);
		::InvalidateRect(hWnd, NULL, TRUE);
	}
}

void WndGridCtlr::selectCol(HWND hWnd, COL_NUM iCol, bool multi)
{
	if (iCol >0 && iCol)
	{
		if (!multi)
		{
			SheetViewer.SetSelectingCell(1, iCol);
			SheetViewer.SetRegionStart(1, iCol);
			::SendMessage(::GetParent(hWnd), MSG_MAIN_SHOWSELECTCELL, (WPARAM)1, (LPARAM)iCol);
		}
		SheetViewer.SetRegionEnd(ROW_MAX, iCol, true , false);
		::InvalidateRect(hWnd, NULL, TRUE);
	}
}

void WndGridCtlr::drawGrid(HDC& hdc)
{
	::SetROP2(hdc, R2_MASKPEN);

	HFONT hFont = MyCreateFont(hdc, TEXT("Times New Roman"),0);
	::DeleteObject(::SelectObject(hdc, hFont));
	
	int* ColWidth = SheetViewer.GetColLinesArr();
	int* RowHeight= SheetViewer.GetRowLinesArr();
	const int nCol = SheetViewer.GetColLinesCount();
	const int nRow = SheetViewer.GetRowLinesCount();

	RECT rect = SheetViewer.GetRegionRect();
	drawRegion(hdc, rect);

	if (ApplicationSetting::ShowHeader)
	{
		drawHeaders(hdc, ColWidth, RowHeight, nCol, nRow, rect);
	}

	if (ApplicationSetting::ShowGridLine)
	{
		drawLines(hdc, ColWidth, RowHeight, nCol, nRow);
	}

	::DeleteObject(::SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;
}



void WndGridCtlr::drawRegion(HDC& hdc, RECT& RegionRect)
{
	// Fill the region with color
	HBRUSH hBrushRegion = ::CreateSolidBrush(UIDrawStyle::CellRegionColor);
	FillRect(hdc, &RegionRect, hBrushRegion);
	::DeleteObject(hBrushRegion);

	// Fill the selecting cell with color
	drawSelecting(hdc);	

	printContent(hdc);
	
	drawRegionBorder(hdc, RegionRect);
}

void WndGridCtlr::drawRegionBorder(HDC& hdc, RECT& RegionRect)
{
	// Draw the region border
	::SelectObject(hdc, ::CreatePen(PS_SOLID, 3, RGB(0,0,0)));
	::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
	::Rectangle(hdc, RegionRect.left, RegionRect.top, RegionRect.right, RegionRect.bottom);
	::DeleteObject(SelectObject(hdc, ::GetStockObject(BLACK_PEN)));
}

void WndGridCtlr::drawSelecting(HDC& hdc)
{
	RECT rect = SheetViewer.GetSelectingRect();
	HBRUSH hBrushSelecting = ::CreateSolidBrush(RGB(255,255,255));
	::FillRect(hdc, &rect, hBrushSelecting);
	::DeleteObject(hBrushSelecting);
}

void WndGridCtlr::drawHeaders(HDC& hdc, int * ColWidth, int * RowHeight, const int nCol, const int nRow, RECT& RegionRect)
{
	// Change the pen to Gray
	::SelectObject(hdc, ::CreatePen(PS_SOLID, 1, UIDrawStyle::HeaderBorderColor));
	::SetTextColor(hdc, UIDrawStyle::HeaderTextColor);
	
	drawRowHeader(hdc, RowHeight, nRow, RegionRect);
	drawColHeader(hdc, ColWidth, nCol, RegionRect);
	
	::DeleteObject(::SelectObject (hdc, ::GetStockObject (BLACK_PEN)));
}


void WndGridCtlr::drawRowHeader(HDC& hdc, int * RowHeight, const int nRow, RECT& RegionRect)
{
	// Making row header's width auto-fits the digits of number
	const int rowHeaderWidth = SheetViewer.GetRowHeaderWidth();
	const int colHeaderHeight = SheetViewer.GetColHeaderHeight();

	// Corner Selecting Button
	::SelectObject(hdc, ::CreateSolidBrush(UIDrawStyle::HeaderCornerColor));
	::Rectangle(hdc, 0, 0, rowHeaderWidth, colHeaderHeight +1);
	::DeleteObject(::SelectObject(hdc, ::GetStockObject(WHITE_BRUSH)));
	// Corner HighLight Line
	HGDIOBJ hOld = ::SelectObject(hdc, ::GetStockObject(WHITE_PEN));
	::MoveToEx(hdc, 1, colHeaderHeight -1 , NULL);
	::LineTo(hdc, 1, 1);
	::LineTo(hdc, rowHeaderWidth -1, 1);
	::DeleteObject(::SelectObject(hdc, hOld));

	// Row Header BkColor
	RECT rect;
	rect.top = SheetViewer.GetColHeaderHeight(); rect.bottom = yClient; 
	rect.left = 0, rect.right = rowHeaderWidth;
	HBRUSH hBrush = ::CreateSolidBrush(UIDrawStyle::HeaderFillColor);
	::FillRect(hdc, &rect, hBrush);
	::DeleteObject(hBrush);
	// Selected Header BkColor
	HBRUSH hBrushSelectedHeader = ::CreateSolidBrush(UIDrawStyle::HeaderSelectedColor);
	int top = RegionRect.top < colHeaderHeight ? colHeaderHeight : RegionRect.top;
	int bottom = RegionRect.bottom <= colHeaderHeight ? colHeaderHeight : RegionRect.bottom;
	RECT rectRowHeader = {0, top + 1, SheetViewer.GetRowHeaderWidth()-1, bottom};
	FillRect(hdc, &rectRowHeader, hBrushSelectedHeader);
	::DeleteObject(hBrushSelectedHeader);

	//Border top
	::MoveToEx(hdc, rect.left, rect.top, NULL);
	::LineTo(hdc, rect.right -1, rect.top);
	//Border right
	::LineTo(hdc, rect.right - 1, rect.bottom);

	int previousLine = SheetViewer.GetColHeaderHeight();
	for (int i = 0; i< nRow; i++)
	{
		// The current row is leftCornerCell.iRow+i
		int currentLine = RowHeight[i];
		currentLine += colHeaderHeight;

		// Draw the Line below this row
		MoveToEx(hdc, 0, currentLine, NULL);
		LineTo(hdc, rowHeaderWidth, currentLine);

		//Write the row number in rectangle
		RECT curRect = {0, previousLine, rowHeaderWidth, currentLine};
		TCHAR num[6] = TEXT("");
		::wsprintf(num, TEXT("%d"), SheetViewer.GetLeftCorner().iRow + i);
		::DrawText(hdc, num ,_tcslen(num),&curRect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);

		previousLine = currentLine;
	}
}

void WndGridCtlr::drawColHeader(HDC& hdc, int * ColWidth, const int nCol, RECT& RegionRect)
{
	int colHeaderHeight = SheetViewer.GetColHeaderHeight();
	int rowHeaderWidth = SheetViewer.GetRowHeaderWidth();

	// Column Header BkColor
	RECT rect;
	rect.top = 0; rect.bottom = colHeaderHeight; 
	rect.left = rowHeaderWidth, rect.right = xClient;
	HBRUSH hBrush = ::CreateSolidBrush(UIDrawStyle::HeaderFillColor);
	::FillRect(hdc, &rect, hBrush);
	::DeleteObject(hBrush);
	// Selected Header BkColor
	HBRUSH hBrushSelectedHeader = ::CreateSolidBrush(UIDrawStyle::HeaderSelectedColor);
	int left = RegionRect.left < rowHeaderWidth ? rowHeaderWidth : RegionRect.left;
	int right = RegionRect.right < rowHeaderWidth ? rowHeaderWidth : RegionRect.right;
	RECT rectColHeader = {left, 1, right, SheetViewer.GetColHeaderHeight()};
	FillRect(hdc, &rectColHeader, hBrushSelectedHeader);
	::DeleteObject(hBrushSelectedHeader);
	
	//Border top
	MoveToEx(hdc, rect.right, rect.top, NULL);
	LineTo(hdc, rect.left-1, rect.top);
	//left
	//MoveToEx(hdc, rect.left-1, rect.top, NULL);
	LineTo(hdc, rect.left-1, rect.bottom);
	//Border bottom
	LineTo(hdc, rect.right, rect.bottom);

	int previousLine = rowHeaderWidth;
	for (int i = 0; i < nCol; i++)
	{
		// The current col is leftCornerCell.iCol+i

		int currentLine = ColWidth[i];
		currentLine += rowHeaderWidth;

		// Draw the Line to the right of this column
		MoveToEx(hdc, currentLine, rect.top, NULL);
		LineTo(hdc, currentLine, rect.bottom);

		//Write the column number in rectangle
		RECT curRect = {previousLine, 0, currentLine, colHeaderHeight};
		TCHAR num[6] = TEXT("");
		SheetViewer.nToA(SheetViewer.GetLeftCorner().iCol+i, num);
		::DrawText(hdc, num ,_tcslen(num),&curRect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);	

		previousLine = currentLine;
	}
}

void WndGridCtlr::drawLines(HDC& hdc, int * ColWidth, int * RowHeight, const int nCol, const int nRow)
{
	int xStart = 0, yStart = 0;
	if (ApplicationSetting::ShowHeader)
	{
		xStart = SheetViewer.GetRowHeaderWidth();
		yStart = SheetViewer.GetColHeaderHeight();
	}	
	// Re-draw the grid according to the size of the window
	// Change the pen to Gray
	SelectObject (hdc, ::CreatePen(PS_SOLID, 1, UIDrawStyle::CellBorderColor));

	RECT unvalidRectHorz = {0,0,0,0};
	RECT unvalidRectVert = {0,0,0,0};

	/* Horizontal Lines */
	int previousLine = yStart;
	for (int i = 0; i< nRow; i++)
	{
		// current row: leftcorner.iRow + i
		if (SheetViewer.GetLeftCorner().iRow + i > ROW_MAX)
		{
			unvalidRectHorz.left = 0;
			unvalidRectHorz.top = previousLine;
			unvalidRectHorz.bottom = yClient;
			unvalidRectHorz.right = xClient;
			break;
		}

		int currentLine = 0;
		currentLine = RowHeight[i];
		if (ApplicationSetting::ShowHeader)
		{
			currentLine += yStart;
		}
		
		// draw the line below current row
		MoveToEx(hdc, xStart, currentLine, NULL);
		LineTo(hdc, xClient, currentLine);

		previousLine = currentLine;

	}
	
	/* Vertical Lines */
	previousLine = xStart;
	for (int i =0; i<nCol; i++)
	{
		// current column: leftcorner.iCol + i
		if (SheetViewer.GetLeftCorner().iCol + i > COL_MAX)
		{
			unvalidRectVert.left = previousLine;
			unvalidRectVert.top = 0;
			unvalidRectVert.bottom = yClient;
			unvalidRectVert.right = xClient;
			break;
		}

		int currentLine = 0;
		currentLine = ColWidth[i];
		if (ApplicationSetting::ShowHeader)
		{
			currentLine += xStart;
		}

		// draw the line to the right of current column
		MoveToEx(hdc, currentLine, yStart, NULL);
		LineTo(hdc, currentLine, yClient);
		
		previousLine = currentLine;
	}
	HBRUSH hBrushShadow = ::CreateSolidBrush(UIDrawStyle::HeaderBorderColor);
	FillRect(hdc, &unvalidRectHorz, hBrushShadow);
	FillRect(hdc, &unvalidRectVert, hBrushShadow);
	::DeleteObject(hBrushShadow);

	::DeleteObject(SelectObject(hdc, ::GetStockObject(BLACK_PEN)));
}

void WndGridCtlr::printContent(HDC& hdc)
{
	::SetTextColor(hdc, COLOR_WINDOWTEXT);
	LinkedList<CellDataItem> CellDataList;
	SheetController objSheetCtlr;
	objSheetCtlr.GetSheetData(CellDataList);

	for (int i = 0; i<CellDataList.GetCount(); i++)
	{
		CellDataItem item;
		CellDataList.GetElement(i+1, item);
		RECT rect = SheetViewer.GetCellRect(item.pos.iRow, item.pos.iCol);
		::SetTextColor(hdc, item.txColor);
		
		if (item.bkColor != CELL_DEFBKCLR)
		{
			HBRUSH hBrush = ::CreateSolidBrush(item.bkColor);
			FillRect(hdc, &rect, hBrush);
			SelectObject(hdc, ::GetStockObject(WHITE_BRUSH));
			::DeleteObject(hBrush);
		}

		HFONT hFont = MyCreateFont(hdc, item.pFontName->c_str(), item.fontAttr);
		HGDIOBJ hOld = ::SelectObject(hdc, hFont);
		DRAWTEXTPARAMS dtp;
		::ZeroMemory(&dtp, sizeof(DRAWTEXTPARAMS));
		dtp.cbSize = sizeof(DRAWTEXTPARAMS);
		dtp.iLeftMargin = 2;
		::DrawTextEx(hdc, (LPWSTR)item.pContent->c_str() , _tcslen(item.pContent->c_str()), &rect, DT_SINGLELINE | item.textHAlign | item.textVAlign, &dtp);
		::SelectObject(hdc, hOld);
		::DeleteObject(hFont);
	}
}

void WndGridCtlr::CreateEditBox(HWND hWnd, RECT rectCell, const CellDataItem* item)
{
	HideEditBox();
	DWORD exStyle = ES_LEFT;
	if (item != 0)
	{
		 if (item->textHAlign == DT_CENTER)
			 exStyle = ES_CENTER;
		 else if(item->textHAlign == DT_RIGHT)
			 exStyle = ES_RIGHT;
		 else
			 exStyle = ES_LEFT;
	}
	hEditBox  = CreateWindowEx(0L, L"Edit", NULL, WS_CHILD
		| WS_VISIBLE| ES_AUTOHSCROLL | ES_WANTRETURN | exStyle , 
		rectCell.left, rectCell.top, rectCell.right - rectCell.left, rectCell.bottom-rectCell.top,
		hWnd, (HMENU) ID_EDITBOX, Application::hInst, 0 );
	EditProc = (WNDPROC) SetWindowLong (hEditBox, GWL_WNDPROC, (LONG) WndGridCtlr::EditBoxProc);

	HDC hdc = GetDC(hWnd);
	HFONT hFont;
	if (item != 0)
		hFont = MyCreateFont(hdc, item->pFontName->c_str(), item->fontAttr);
	else
		hFont = MyCreateFont(hdc, CELL_DEF_FONT_NAME, CELL_DEF_FONT_ATTR);
	::SendMessage(hEditBox, WM_SETFONT, (WPARAM) hFont, true);
	::ReleaseDC(hWnd, hdc);

	::SetFocus(hEditBox);
}

void WndGridCtlr::HideEditBox()
{
	if (::GetWindowLong(hEditBox,GWL_ID) == 0)
		return ;

	// Already in editing mode
	// Get the Text
	TCHAR szContent[CELL_CONTENT_MAX] = TEXT("");
	WORD lenText = (WORD) SendMessage(hEditBox, EM_LINELENGTH, (WPARAM) 0, (LPARAM) 0); 
	*((LPWORD)szContent) = lenText;

	::SendMessage(hEditBox, EM_GETLINE, (WPARAM) 0, (LPARAM)szContent); 

	SheetController objSheetCtlr;
	objSheetCtlr.ModifyContent( SheetViewer.GetSelecting(), szContent);

	::DestroyWindow(hEditBox);
}

HFONT WndGridCtlr::MyCreateFont(HDC hdc, const TCHAR * szFaceName, int iAttributes)
{
	FLOAT      cxDpi, cyDpi ;
	HFONT      hFont ;
	LOGFONT    lf ;
	POINT      pt ;
	TEXTMETRIC tm ;

	cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;
	cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;

	pt.x = (int) (0  * cxDpi / 72) ;
	pt.y = (int) (105 * cyDpi / 72) ;

	GetTextMetrics (hdc, &tm) ;

	lf.lfHeight         = (LONG)(- (int) (fabs((long double)(pt.y)) / 10.0 + 0.5) * ApplicationSetting::Zooming);
	lf.lfWidth          = (LONG)((int) (tm.tmAveCharWidth *	fabs ((long double)pt.x) / fabs ((long double)pt.y) + 0.5) * ApplicationSetting::Zooming);
	lf.lfEscapement     = 0 ;
	lf.lfOrientation    = 0 ;
	lf.lfWeight         = iAttributes & CELL_FONT_ATTR_BOLD		 ? 700 : 0 ;
	lf.lfItalic         = iAttributes & CELL_FONT_ATTR_ITALIC    ?   1 : 0 ;
	lf.lfUnderline      = iAttributes & CELL_FONT_ATTR_UNDERLINE ?   1 : 0 ;
	lf.lfStrikeOut      = iAttributes & CELL_FONT_ATTR_STRIKEOUT ?   1 : 0 ;
	lf.lfCharSet        = DEFAULT_CHARSET ;
	lf.lfOutPrecision   = 0 ;
	lf.lfClipPrecision  = 0 ;
	lf.lfQuality        = 0 ;
	lf.lfPitchAndFamily = 0 ;
	lstrcpy (lf.lfFaceName, szFaceName) ;

	hFont = CreateFontIndirect(&lf);
	return hFont ;
}

void WndGridCtlr::CheckToolBarButton()
{
	Controls::ReSetToolBar();
	CellDataItem item;
	SheetController objSheetCtlr;
	if (objSheetCtlr.GetCellContent(SheetViewer.GetSelecting(), item))
	{
		Controls::SetToolBarButton(ID_FONT_BOLD, (item.fontAttr & CELL_FONT_ATTR_BOLD)!=0);
		Controls::SetToolBarButton(ID_FONT_ITALIC, (item.fontAttr & CELL_FONT_ATTR_ITALIC)!=0);
		Controls::SetToolBarButton(ID_FONT_UNDERLINE, (item.fontAttr & CELL_FONT_ATTR_UNDERLINE)!=0);
		Controls::SetToolBarButton(ID_FONT_STRICK,(item.fontAttr & CELL_FONT_ATTR_STRIKEOUT)!=0);
		Controls::SetToolBarButton(ID_ALIGN_LEFT, (item.textHAlign & DT_LEFT)!=0);
		Controls::SetToolBarButton(ID_ALIGN_CENTER, (item.textHAlign & DT_CENTER)!=0);
		Controls::SetToolBarButton(ID_ALIGN_RIGHT, (item.textHAlign & DT_RIGHT)!=0);
		Controls::SetToolBarButton(ID_VALIGN_TOP, (item.textVAlign & DT_TOP)!=0);
		Controls::SetToolBarButton(ID_VALIGN_CENTER, (item.textVAlign & DT_VCENTER)!=0);
		Controls::SetToolBarButton(ID_VALIGN_BOTTOM, (item.textVAlign & DT_BOTTOM)!=0);
	}
}

void WndGridCtlr::CheckMenu(HMENU hMenu)
{
	CellDataItem item;
	SheetController objSheetCtlr;
	if (objSheetCtlr.GetCellContent(SheetViewer.GetSelecting(), item))
	{
		CheckMenuItem(hMenu, ID_FONT_BOLD, (item.fontAttr & CELL_FONT_ATTR_BOLD)!=0);
		CheckMenuItem(hMenu, ID_FONT_ITALIC, (item.fontAttr & CELL_FONT_ATTR_ITALIC)!=0); 
		CheckMenuItem(hMenu, ID_FONT_UNDERLINE, (item.fontAttr & CELL_FONT_ATTR_UNDERLINE)!=0);
		CheckMenuItem(hMenu, ID_FONT_STRICK,(item.fontAttr & CELL_FONT_ATTR_STRIKEOUT)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_LEFT, (item.textHAlign & DT_LEFT)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_CENTER, (item.textHAlign & DT_CENTER)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_RIGHT, (item.textHAlign & DT_RIGHT)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_TOP, (item.textVAlign & DT_TOP)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_CENTER, (item.textVAlign & DT_VCENTER)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_BOTTOM, (item.textVAlign & DT_BOTTOM)!=0);
	}
	else
	{
		CheckMenuItem(hMenu, ID_FONT_BOLD, (CELL_DEF_FONT_ATTR & CELL_FONT_ATTR_BOLD)!=0);
		CheckMenuItem(hMenu, ID_FONT_ITALIC, (CELL_DEF_FONT_ATTR & CELL_FONT_ATTR_ITALIC)!=0); 
		CheckMenuItem(hMenu, ID_FONT_UNDERLINE, (CELL_DEF_FONT_ATTR & CELL_FONT_ATTR_UNDERLINE)!=0);
		CheckMenuItem(hMenu, ID_FONT_STRICK,(CELL_DEF_FONT_ATTR & CELL_FONT_ATTR_STRIKEOUT)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_LEFT, (CELL_DEFHALIGN & DT_LEFT)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_CENTER, (CELL_DEFHALIGN & DT_CENTER)!=0);
		CheckMenuItem(hMenu, ID_ALIGN_RIGHT, (CELL_DEFHALIGN & DT_RIGHT)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_TOP, (CELL_DEFVALIGN & DT_TOP)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_CENTER, (CELL_DEFHALIGN & DT_VCENTER)!=0);
		CheckMenuItem(hMenu, ID_VALIGN_BOTTOM, (CELL_DEFHALIGN & DT_BOTTOM)!=0);
	}
}

void WndGridCtlr::CheckMenuItem(HMENU hMenu, int nID, bool checked)
{
	if (checked)
		::CheckMenuItem(hMenu, nID, MF_CHECKED);
	else
		::CheckMenuItem(hMenu, nID, MF_UNCHECKED);
}